package com.liuya.safe.policy.controller;

import com.liuya.base.BaseController;
import com.liuya.common.exception.EntityExistException;
import com.liuya.common.SpringUtils;
import com.liuya.common.StringUtil;
import com.liuya.common.WebUtil;
import com.liuya.safe.exception.AuthException;
import com.liuya.safe.model.SafeQuery;
import com.liuya.safe.policy.handler.QueryDesignHandler;
import com.liuya.safe.policy.handler.QueryRawHandler;
import com.liuya.safe.policy.handler.QueryTestHandler;
import com.liuya.safe.policy.service.QueryManagerService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.StringReader;

import com.liuya.db.sql.xml.Column;
import com.liuya.db.sql.xml.Parameter;
import com.liuya.db.sql.xml.QueryType;
import com.liuya.db.sql.xml.types.QueryTypeTypeType;
import org.springframework.web.bind.annotation.ResponseBody;


/**
 * 手工模式设计查询
 */
@Controller
@Api(value = "手工模式编辑查询策略", description = "手工模式编辑查询策略")
@RequestMapping(value = "queryRaw")
public class QueryRawController extends BaseController {

    @ApiOperation(value = "跳转到手式页面")
//    @RequiresPermissions("sys.queryRaw.editPolicy")
    @RequestMapping(value = "/editPolicy")
    public Object editPolicy(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        String id = WebUtil.getStringParameter(req, "id", "0");
        modelMap.addAttribute("id", id);

        return "policy/query/raw";
    }

    @ApiOperation(value = "跳转到SQL页面")
//    @RequiresPermissions("sys.queryPolicy.rawSql")
    @RequestMapping(value = "/rawSql")
    public Object rawSql(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        return "policy/query/rawSql";
    }

    @ApiOperation(value = "跳转到参数页面")
//    @RequiresPermissions("sys.queryPolicy.param")
    @RequestMapping(value = "/param")
    public Object param(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        return "policy/query/rawParam";
    }

    @ApiOperation(value = "跳转映射页面")
//    @RequiresPermissions("sys.queryPolicy.mapping")
    @RequestMapping(value = "/mapping")
    public Object mapping(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        return "policy/query/rawMapping";
    }

    @ApiOperation(value = "跳转编辑参数页面")
//    @RequiresPermissions("sys.queryPolicy.preEditParam")
    @RequestMapping(value = "/preEditParam")
    public Object preEditParam(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        String strIndex = req.getParameter("index");
        if (!StringUtil.isEmpty(strIndex)) {
            int index = Integer.parseInt(strIndex);
            Parameter param = handler.getParameter(index);
            req.setAttribute("param", param);
        }
        return "policy/query/editParam";
    }

    @ApiOperation(value = "保存编辑后的参数")
//    @RequiresPermissions("sys.queryPolicy.editParam")
    @RequestMapping(value = "/editParam")
    @ResponseBody
    public Object editParam(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");

        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        int index = WebUtil.getIntParameter(req, "index", -1);

        String type = req.getParameter("type");
        String key = req.getParameter("key");

        handler.updateParameter(index, type, key);

        updateHandler(req, handler);
        return true;
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.addParam")
    @RequestMapping(value = "/addParam")
    @ResponseBody
    public Object addParam(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        String type = req.getParameter("type");
        String key = req.getParameter("key");

        handler.addParameter(type, key);
        updateHandler(req, handler);
        return true;
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.deleteParam")
    @RequestMapping(value = "/deleteParam")
    @ResponseBody
    public Object deleteParam(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        int index = WebUtil.getIntParameter(req, "index", -1);

        handler.deleteParameter(index);
        updateHandler(req, handler);
        return true;
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.moveParam")
    @RequestMapping(value = "/moveParam")
    @ResponseBody
    public Object moveParam(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        int index = WebUtil.getIntParameter(req, "index", -1);
        String direct = req.getParameter("direct");

        handler.moveParameter(direct, index);
        updateHandler(req, handler);
        return true;
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.preEditProperty")
    @RequestMapping(value = "/preEditProperty")
    public Object preEditProperty(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        String strIndex = req.getParameter("index");
        if (!StringUtil.isEmpty(strIndex)) {
            int index = Integer.parseInt(strIndex);
            Column column = handler.getColumn(index);

            req.setAttribute("column", column);
        }

        String[][] mappingClassPropertyAndTypes = handler.getMappingClassPropertyAndTypes();
        req.setAttribute("mappingClassPropertyAndTypes", mappingClassPropertyAndTypes);

        return "policy/query/editProperty";
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.editProperty")
    @RequestMapping(value = "/editProperty")
    @ResponseBody
    public Object editProperty(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        int index = WebUtil.getIntParameter(req, "index", -1);
        String property = req.getParameter("property");
        boolean readOnly = WebUtil.getBooleanParameter(req, "readOnly", false);
        String columnName = req.getParameter("columnName");

        int sindex = property.indexOf("<");
        String javaProp = property.substring(0, sindex - 1).trim();
        String javaType = property.substring(sindex + 1, property.length() - 1).trim();

        handler.updateProperty(index, columnName, javaProp, javaType, readOnly);
        updateHandler(req, handler);
        return true;
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.addProperty")
    @RequestMapping(value = "/addProperty")
    @ResponseBody
    public Object addProperty(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        String property = req.getParameter("property");
        boolean readOnly = WebUtil.getBooleanParameter(req, "readOnly", false);
        String columnName = req.getParameter("columnName");

        int index = property.indexOf("<");
        String javaProp = property.substring(0, index - 1).trim();
        String javaType = property.substring(index + 1, property.length() - 1).trim();

        handler.addProperty(columnName, javaProp, javaType, readOnly);
        updateHandler(req, handler);
        return true;
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.deleteProperty")
    @RequestMapping(value = "/deleteProperty")
    @ResponseBody
    public Object deleteProperty(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        int index = WebUtil.getIntParameter(req, "index", -1);

        handler.deleteProperty(index);
        updateHandler(req, handler);
        return true;
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.moveProperty")
    @RequestMapping(value = "/moveProperty")
    @ResponseBody
    public Object moveProperty(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        int index = WebUtil.getIntParameter(req, "index", -1);
        String direct = req.getParameter("direct");

        handler.moveProperty(direct, index);
        updateHandler(req, handler);
        return true;
    }

    @ApiOperation(value = "返回设计器主页面")
//    @RequiresPermissions("sys.queryPolicy.returnMain")
    @RequestMapping(value = "/returnMain")
    public Object returnMain(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);
        String id = WebUtil.getStringParameter(req, "id", "0");
        modelMap.addAttribute("id", id);
        // remove handler from session
        req.getSession().removeAttribute(getHandlerAttributeKey(req));

        return "redirect:/queryDesign/editPolicy.do";
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.setMappingClass")
    @RequestMapping(value = "/setMappingClass")
    @ResponseBody
    public Object setMappingClass(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        String mappingClass = req.getParameter("mappingClass");
        handler.setMappingClass(mappingClass);
        updateHandler(req, handler);
        return true;
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.setRawSql")
    @RequestMapping(value = "/setRawSql")
    @ResponseBody
    public Object setRawSql(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        String rawSql = req.getParameter("rawSql");
        handler.setRawSql(rawSql);
        updateHandler(req, handler);
        return true;
    }

    @ApiOperation(value = "编辑查询策略")
//    @RequiresPermissions("sys.queryPolicy.save")
    @RequestMapping(value = "/save")
    @ResponseBody
    public Object save(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        QueryRawHandler handler = getHandler(req);
        req.setAttribute("handler", handler);

        // remove handler from session
        req.getSession().removeAttribute(getHandlerAttributeKey(req));

        String id = WebUtil.getStringParameter(req, "id", "-23");
        QueryManagerService queryManager = (QueryManagerService) SpringUtils.getBean("queryManagerService");
        try {
            handler.save(id, queryManager);

            updateHandler(req, handler);
            return true;
        } catch (EntityExistException e) {
            return false;
        }
    }

    public QueryRawHandler createHandler(HttpServletRequest req) {
        String id = WebUtil.getStringParameter(req, "id", "0");
        QueryManagerService queryManager = (QueryManagerService) SpringUtils.getBean("queryManagerService");
        SafeQuery query = queryManager.getQuery(id);

        com.liuya.db.sql.xml.QueryType xmlQuery;
        try {
            xmlQuery = com.liuya.db.sql.xml.Query.unmarshal(new StringReader(query.getXmlContent()));
        } catch (Exception e) {
            throw new AuthException(e);
        }

        return new QueryRawHandler(xmlQuery);
    }

    public String getHandlerAttributeKey(HttpServletRequest req) {
        int id = WebUtil.getIntParameter(req, "id", 0);
        return "_$safeQuery_" + id;
    }

    private QueryRawHandler getHandler(HttpServletRequest req) {
        String oper = req.getParameter("oper");
        String key = getHandlerAttributeKey(req);
        Object obj = req.getSession().getAttribute(key);
        QueryRawHandler handler = null;

        if (obj == null || "loadFresh".equals(oper)) {
            handler = createHandler(req);

            // save into session, will be removed when policy is saved
            req.getSession().setAttribute(key, handler);
        } else if (obj instanceof QueryDesignHandler) {
            QueryDesignHandler designHandler = (QueryDesignHandler) obj;
            QueryType query = designHandler.getQuery();
            handler = new QueryRawHandler(query);
            req.getSession().setAttribute(key, handler);

            // set to raw sql type
            query.setIsRawSQL(true);
            query.setType(QueryTypeTypeType.SQL);
        } else if (obj instanceof QueryTestHandler) {
            QueryTestHandler rawHandler = (QueryTestHandler) obj;
            QueryType query = rawHandler.getQuery();
            handler = new QueryRawHandler(query);
            req.getSession().setAttribute(key, handler);
        } else {
            handler = (QueryRawHandler) obj;
        }

        return handler;
    }

    private void updateHandler(HttpServletRequest req, Object handler) {
        String key = getHandlerAttributeKey(req);
        HttpSession session = req.getSession();
        session.setAttribute(key, handler);
    }
}
